#include "treeNode.h"

void treedebug(char *format, ...)
{
#ifdef LOCAL
	va_list args;
	va_start(args, format);
	vprintf(format, args);
	va_end(args);
#endif
}

void traval_tree_preorder(tree_t root, traval_func_t func, int depth);
void traval_tree_inorder(tree_t root, traval_func_t func, int depth);
void traval_tree_postorder(tree_t root, traval_func_t func, int depth);
void _print_node(tree_node_t *node, int depth);
void _free_node(tree_node_t *node, int depth);

tree_node_t *create_and_init_node(
	char *name, 
	node_data_t data, 
	node_type_t node_type, 
	int line_index)
{
	tree_node_t *node = (tree_node_t *)malloc(sizeof(tree_node_t));
	node->son = NULL;
	node->sibling = NULL;
	node->line_index = line_index;
	node->node_type = node_type;

	node->data.data_type = data.data_type;
	switch (data.data_type)
	{
	case INT_DATA:
		node->data.data = (int *)malloc(sizeof(int));
		*(int *)node->data.data = *(int *)data.data;
		break;
	case FLOAT_DATA:
		node->data.data = (float *)malloc(sizeof(float));
		*(float *)node->data.data = *(float *)data.data;
		break;
	case TYPE_DATA:
	case ID_DATA:
	case STRING_DATA:
		node->data.data = (char *)malloc(strlen((char *)data.data) + 1);
		strcpy((char *)node->data.data, (char *)data.data);
		break;
	case DEFAULT_DATA:
		node->data.data = NULL;
		break;
	default:
		node->data.data = NULL;
		fprintf(stderr, "Error: data_type is not defined.\n");
		break;
	}
	strcpy(node->name, name);
	return node;
}

void traval_tree(tree_t root, traval_type_t traval_type, traval_func_t func)
{
	if (func == NULL)
	{
		return;
	}
	switch (traval_type)
	{
	case TRAVAL_PREORDER:
		traval_tree_preorder(root, func, 0);
		break;
	case TRAVAL_INORDER:
		traval_tree_inorder(root, func, 0);
		break;
	case TRAVAL_POSTORDER:
		traval_tree_postorder(root, func, 0);
		break;
	default:
		fprintf(stderr, "Error: traval_type is not defined.\n");
		break;
	}
}
void add_sons(tree_node_t *parent, int son_num, ...)
{}

void destroy_tree(tree_t *ptree)
{
	tree_t root = *ptree;
	traval_tree(root, TRAVAL_POSTORDER, _free_node);
	*ptree = NULL;
}

void print_tree(tree_t *ptree)
{
	tree_t root = *ptree;
	traval_tree(root, TRAVAL_PREORDER, _print_node);
}

void traval_tree_preorder(tree_t root, traval_func_t func, int depth)
{
	if(root == NULL)
	{
		return;
	}
	func(root, depth);
	traval_tree_preorder(root->son, func, depth + 1);
	traval_tree_preorder(root->sibling, func, depth);
}

void traval_tree_inorder(tree_t root, traval_func_t func, int depth)
{
	// TBD
}

void traval_tree_postorder(tree_t root, traval_func_t func, int depth)
{
	if(root == NULL)
	{
		return;
	}
	traval_tree_postorder(root->son, func, depth + 1);
	traval_tree_postorder(root->sibling, func, depth);
	func(root, depth);
}

void _print_node(tree_node_t *node, int depth)
{
	for (int i = 0; i < depth; i++)
	{
		printf("  ");
	}
	printf("%s", node->name);
	switch (node->node_type)
	{
	case SYNTAX_NODE:
		treedebug("LEX_NODE\n");
		printf(" (%d)", node->line_index);
		break;
	case LEX_NODE:
		treedebug("SYNTAX_NODE\n");
		switch (node->data.data_type)
		{
		case INT_DATA:
			treedebug("INT\n");
			printf(": %d", *(int *)node->data.data);
			break;
		case FLOAT_DATA:
			treedebug("FLOAT\n");
			printf(": %f", *(float *)node->data.data);
			break;
		case STRING_DATA:
			treedebug("STRING\n");
			printf(": %s", (char *)node->data.data);
			break;
		case TYPE_DATA:
			treedebug("TYPE\n");
			printf(": %s", (char *)node->data.data);
			break;
		case ID_DATA:
			treedebug("ID\n");
			printf(": %s", (char *)node->data.data);
			break;
		case DEFAULT_DATA:
			treedebug("DEFAULT\n");
			if(node->data.data)
				printf(": %s", (char *)node->data.data);
			break;
		default:
			fprintf(stderr, "Error: data_type is not defined.\n");
			break;
		}
		break;
	default:
		fprintf(stderr, "Error: node_type is not defined.\n");
		break;
	}
	printf("\n");
}

void _free_node(tree_node_t *node, int depth)
{
	if (node->data.data != NULL)
	{
		free(node->data.data);
	}
	free(node);
}

